Real time communication under Windows
By Peter Hawken
Written February 2004
The project
A client that demanded a high performance battery based video system triggered a new interest in PC programming. The brief: To develop a small video camera and recorder power supply that would provide 8 hours of use with a one hour charge and the whole unit to operate from a mains supply or a car cigarette lighter and would require no maintenance by the user. The users in this case are law enforcement personnel who needed a secret filming device concealed in a shoulder bag or brief case. Maintenance is not high on the list of priorities for the investigators, so the charging process has to be completely automatic to maximise running time and to maintain the battery pack in good condition at all times. The choice of nickel metal-hydride batteries was obvious in terms of performance and shelf life. Lithium Ion batteries, although capable of storing more energy for a given weight and volume have a limited life regardless of the amount of use and can drop to 40% capacity with alarming speed if they are stored in a warm environment. They also have a minimum charging time of around 2 hours if they are to be fully charged. NiMh batteries can be fully charged in under one hour if care is taken to terminate the charge at the right time. 500 to 1000 charges are quite possible but regular testing of the battery pack is needed to avoid failure of the system at a critical time. There are no retakes in crime investigation. For reliability, the batteries are bolted into place and soldered. Removing them is undesirable unless is it for a replacement pack.
Battery maintenance and testing needed to be automatic and reliable. Our solution was to send data to a pc which would record information on charging and discharging over a period of about 10 hours. This covers a one hour charge period, a one hour idle period and then an 8 hour discharge. The prototype unit was connected to a voltmeter (and a very bored technician) so it was important to produce a recording device to automate the process. Recording data gives us an opportunity to compare battery packs over a period of time and replace them when they show signs of age.
Selection of language and coding
Previously, all my PC programming has been done in Pascal and DOS. A search of many languages and packages unearthed Liberty Basic as a simple language, reasonably well documented and with documented support for the PC serial ports. This was vital if we were to produce operating and reliable code in a reasonable amount of time. From past experience, using hardware ports in a PC can often give rise to compatibility problems; even more so today with the wider range of operating systems, port hardware, BIOS variations and so on. It is worth giving a mention to the choice of serial rather than parallel. Both ports are bi directional, both can handle 8 bit bytes with ease and LB can interface with either of them. Our choice of serial was dictated by the number of output pins on the controller chip in our battery controller. As the chip has only 13 input / ouput pins and we have used 8 of them already, a parallel port that requires 8 pins plus one or two more for strobe lines was out of the question. Additionally, serial ports can typically drive 30 metres or more at high speed and the signal is robust enough to cause no reliability problems. Finally, the component count is lower for a serial port and shows s cost saving in most applications.
The code is relatively simple but because it is very specialised, only portions are shown here for clarity.
One of the problems to be overcome is the opening and closing of devices and handles. Attempting to open a port already open or a non existent port will produce an error that needs to be trapped with oncomerror, in this case:
oncomerror [PortError]
Closing a communication port that isn’t open will dump the user right out of the programme and I haven’t yet found a way to trap this error. Using the variable Comstate$ in the programme segments below tracks the port status and it is used to avoid opening a second port or attempting to close a port that isn’t open. If there is a more elegant solution, I will be very happy to hear it. I used a menu selection to select the port number and open it with this routine
[SelectPort]
if ComState$ = "false" then
prompt "enter port number to be used."; portnum$
com$ = "COM"; portnum$; ":19200,n,8,1,ds0"
open com$ for random as #comm
ComState$ = "true"
else
notice "Communication port ";portnum$;" already open. Close this port before selcting another"
end if
wait
portnum$ is predefined and filled with the default port number (1 on first use of the programme and then the last used port number for subsequent uses). If the user tries to start the monitoring without setting the port number, the programme will attempt to open the default port without any prompting. It will return the error message mentioned below if there is a problem opening the port. The application uses a micro crontroller to send an 8 bit data stream at 19200 baud so there was no need to provide any port adjustments.
To track the port status, ComState$ was predefined and “false” assigned to it. Only when the port has been successfully opened is this changed to “true”. Note that if there is an error opening the port it will be trapped before ComState$ is changed.
[porterror]
ErrString$ = "Error: "; ComError$; " Serial port "; ComPortNumber
notice ErrString$
ComState$ = "false"
wait
Note that the ComState$ is set to “false” to ensure the status is kept up to date.
Finally, closing the port uses just one line:
if ComState$ = "true" then close #comm
This will check the recorded port status and only try to close the port if it is open. This avoids the possibility of being dumped out of the programme because the handle does not exist. I have not so far found a way of checking the existence of a file handle within LB. If there was one, it would provide a means of checking whether or not the port is open. Please remember that I am a novice when it comes to Liberty Basic, so I don’t claim that any of the code here is the tidiest or the most efficient but it does work!
How the data is generated
One of the great features of microcontrollers is that they are incredibly small. The whole computer processor, programme memory, data memory, input and output are all on a single chip. This great feature is also a great problem from time to time. Because they are so small, their programme memory is as little as 512 bytes in the smaller devices with as few as 32 bytes of RAM. The art of programming such a device is to squeeze as much functionality into as small a space as you can manage. The custom of using verbose data strings with 10 byte headers and even longer terminating strings are not those of the microcontroller programmer. The data we need consists of several voltage readings, timers and status indicators. The voltages are read by the controller about 500 times each second. The processor will send the data to its serial port every half second. So we send a start byte to synchronise the two devices, two voltage values in one byte each, two time values, also one byte each and a status byte to indicate the state of several switches in the camera system. The total is 6 bytes of data sent twice each second. The start byte is always 255 (FFH) and is the only byte that has that value. We look for the byte with the following:
while asc(dataread$) <> 255
if lof(#comm)>0 then
dataread$ = INPUT$(#comm, 1)
end if
scan
if TestRun = 0 then exit while
wend
Unlike the Pascal language that I have spent many years using, Liberty Basic has no data type of ‘byte’ so we look for valid data at the port and then read it as a one character string. Asc(dataread$) converts the character into the ascii numeric code for the character and we arrive at the byte value received at the port. We keep doing this until the byte value of the character is 255 which terminates the WHILE WEND loop. A scan is put into the loop to provide a means of reading other input while we look for the first byte. In the event that no data is being sent, this provides a means of exiting the routine. Once the start byte has been found, it is discarded and the programme looks for the remaining 5 bytes. The first byte is read in the following manner
while lof(#comm)=0
scan
if TestRun = 0 then exit while
wend
VBatt$ = INPUT$(#comm, 1)
VBatt = asc(VBatt$)
Once again, we look for valid data at the port and we also have the scan and exit while instructions as an escape route. The one character string is read and converted to a value using the ASC() instruction. As a single byte value, the range will be between 0 and 254 (255 is prohibited as this is the start byte value). The remainder of the code processes the number to arrive at a real voltage (between 7 and 11 volts in this case). Four more bytes are read in the same way and the process is repeated for the duration of the test.
It is quite clear by now that the interpretation of the data is linked closely with the microcontroller operation. One must have detailed knowledge of the device in order to display intelligent information. It is for this reason of course that a standard terminal programme won’t do the job. In this case, as we have designed all the hardware and software for the battery management system, this is no problem. For applications where the transmitting device is not known in depth, a lot of time can be put into identifying the type of communication, the speed, number of bits etc and then it is possible to analyse the data being sent. Whatever the device, this is never a trivial task and in our experience it is worth spending a great deal of time to obtain the technical information from the manufacturer. This will save time in almost all instances.
The technical bits (and bytes) of the microcontroller
Microcontrollers are generally identified as single chip computers. From the smallest 8 pin devices right up to chips that have more processing power than early PC’s they find their way into a vast range of domestic, commercial and industrial equipment as the brains or interface of the product. Our choice is the PIC by Microchip and no doubt we shall continue with them because they perform satisfactorily for our purposes and of course, knowledge of the product means we have a library of software ready to be used. There are several other manufacturers and all have their own strengths and weaknesses. After many years working with 6502 and Z80 processors, they took some getting used to. Unlike conventional processors, they tend to have a very small instruction set and it is up to the programmer to make use of the set to his best advantage. Although there are PICs with built in serial ports, we have chosen devices that don’t have ready made ports. This is partly for cost reasons and partly for compatibility of products and software. The cost saving for each device is small, but we have purchased almost 2000 of them in the last 18 months and the savings build up. The serial ports have been implemented in software and operate as well as any hardware device. Because we can control what we need to send, we choose a standard of 19200 baud with 8 bits and no parity. The parity bit that was so important back in the days of remote terminals is largely redundant as RS232 is these days a means of local communication rather than stretching the length of an office building. Our requirements are for a cable of as much as one metre long sometimes rather shorter that the 100M or more that is the maximum length.
One of the beauties of PIC programming in real time is the instruction time. Each instruction takes 4 clock cycles. Therefore a 4Mhz clock executes one instruction every microsecond. Simply counting the instructions will give an accurate guide of the time taken. So hardware nerds will know that one bit at 19200 baud will be 52 uS long before the next bit is sent out. (It’s actually 52.08uS but the .08 doesn’t worry any RS232 device, so we cheat and use a 4MHz clock and accept this small error). We simply need to take a byte, read bit0 and then rotate the byte and read the new bit0 52 instructions later and so on until all 8 bits have been read and sent to an output pin. Multi-tasking isn’t a major concern of most PIC programmers, but while waiting for 52uS, it is quite possible to run a small subroutine of 40 to 45 instructions and get back to the business of the serial port in time for the next bit. It is surprising how much can be achieved in such a small number of instructions especially without the burden of an operating system.
The final stage is to get the voltage level right. The output from any logic chip such as a PIC is 0V for a ‘0’ or 5V for a ‘1’. RS 232 is +3 to +25V for a ‘0’ and -3 to -25V for a ‘1’. The RS232 driver also must be capable of surviving a short to any other RS232 line. Now we could be clever and design current limiting inverter circuits that run on a split supply rail or we can be lazy and buy the chip that does the job. We are lazy and for under £1 (or about $1) a MAX232 chip by Maxim will do the job for two inputs and two outputs.
Data Presentation
For this application, it is important to obtain accurate voltage and time readings, so the numbers are displayed rather than a graphical representation. The graph that is produced at the end of the test is more as a confirmation of correct charge and discharge slopes, but it doesn’t perform well as an indicator of precise voltages. As a result, the data is displayed in a table using statictext. It is not the most exciting of displays, but watching a battery go flat isn’t exactly an exciting pastime. This is partly an excuse. As a techie rather than a designer, I have little interest in making the display pretty or dynamic. More importantly, the application here does not need to be monitored continuously so there is no reason to spend a large amount of time on the display. Having said that, I am sure that the data window will be enhanced as time goes on. At least we have made use of the font instruction to display large characters that can be read from the far side of the workshop.
For storage and graph production, the LB software creates a file for each test. For simplicity, we have used the unit serial number, the type of test and the date followed by .CSV to create the file. The first line is the same data but written as a title. The second line is for column headings and the third is the first set of data. The values are written every minute with a comma to separate each value (Comma Separated Value) and a carriage return at the end of the values before the next set of data are written. As luck would have it, Excel can read this file directly without any import routine and it is very simple to create. The graph function of Excel produces graphical data from this table and this is the final piece of information stored and presented to the client as part of the service routine
The next phase of the development will be to use the battery monitor software to generate a line graph of voltage against time. It will be useful to see the graph as the test progresses and therefore the graph window will need to change size and scale as the graph grows. Some pointers already received from Bill J have taken us forward and I am confident that this phase will be done in the near future.
Future applications
Once the basic data input software is created, the possibilities are almost endless for new applications. From my own point of view, as a gadget man, I am tempted to monitor and record everything for which I can find a sensor or transducer. My wife tells me that I am not allowed to strap an accelerometer to the family cat to record how fast and high she jumps during the day. Feline activities aside, the use of a microcontroller as an interface to the real world creates opportunities that until recently were difficult and expensive to implement. A look at the sensor and transducer section of any component catalogue will generate ideas to swamp even the most prolific programmer.
Peter Hawken works for Speak Easy Europe in England, specialists in control, video and audio engineering. Information contained in this article is used with permission of Speak Easy Europe Ltd and may not be reproduced for commercial use.
Thanks are due to Alyce Watson for assistance with LB language during the coding of the programme and to Bill J for his ideas and guidance in the writing of this article
Further reading
A serial port primer and LB basics [http://lbdev.5u.com/current.html#article_1]
ARTICLE : Serial Communication with Liberty Basic by Dean Jolly
[]ttp://babek.info/libertybasicfiles/lbnews/nl97/3.htm]